//SPDX-FileCopyrightText: Copyright 2022-2024 深圳市同心圆网络有限公司
//SPDX-License-Identifier: GPL-3.0-only

package project_requirement_api_serv

import (
	"context"
	"time"

	"atomgit.com/openlinksaas-org/api-server/api_common"
	"atomgit.com/openlinksaas-org/api-server/dao"
	"atomgit.com/openlinksaas-org/api-server/dao/requirement_dao"
	"atomgit.com/openlinksaas-org/api-server/utils"
	"atomgit.com/openlinksaas-org/proto-gen-go.git/notices/notices_requirement"
	"atomgit.com/openlinksaas-org/proto-gen-go.git/project_requirement_api"
	"go.mongodb.org/mongo-driver/mongo"
)

func (apiImpl *ProjectRequirementApiImpl) SetKanoInfo(ctx context.Context, req *project_requirement_api.SetKanoInfoRequest) (*project_requirement_api.SetKanoInfoResponse, error) {
	sessionItem, ok := dao.CacheDao.GetSession(ctx, req.SessionId)
	if !ok {
		return &project_requirement_api.SetKanoInfoResponse{
			Code:   project_requirement_api.SetKanoInfoResponse_CODE_WRONG_SESSION,
			ErrMsg: "会话不存在",
		}, nil
	}
	projectItem, _, roleItem, err := utils.GetProjectMemberRole(ctx, req.ProjectId, sessionItem.UserId)
	if err == utils.ErrNoProject {
		return &project_requirement_api.SetKanoInfoResponse{
			Code:   project_requirement_api.SetKanoInfoResponse_CODE_NO_PROJECT,
			ErrMsg: "项目不存在",
		}, nil
	} else if err == utils.ErrNoRole {
		return &project_requirement_api.SetKanoInfoResponse{
			Code:   project_requirement_api.SetKanoInfoResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	} else if err != nil {
		return nil, err
	}

	//检查需求是否存在
	reqItem, err := requirement_dao.RequirementInfoDao.Get(ctx, req.ProjectId, req.RequirementId)
	if err != nil {
		return &project_requirement_api.SetKanoInfoResponse{
			Code:   project_requirement_api.SetKanoInfoResponse_CODE_NO_REQUIRE_MENT,
			ErrMsg: "需求不存在",
		}, nil
	}

	if !(projectItem.OwnerUserId == sessionItem.UserId || roleItem.BasicInfo.Admin || sessionItem.UserId == reqItem.CreateUserId) {
		return &project_requirement_api.SetKanoInfoResponse{
			Code:   project_requirement_api.SetKanoInfoResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	}
	dbSess, err := dao.StartSession()
	if err != nil {
		return nil, err
	}
	defer dao.EndSession(dbSess)

	ret, err := dbSess.WithTransaction(ctx, func(sessCtx mongo.SessionContext) (interface{}, error) {
		err = requirement_dao.KanoInfoDao.Set(sessCtx, &requirement_dao.KanoInfoDbItem{
			RequirementId: req.RequirementId,
			LikeVsRow:     requirement_dao.ConvertKanoRow(req.KanoInfo.LikeVsRow),
			ExpectVsRow:   requirement_dao.ConvertKanoRow(req.KanoInfo.ExpectVsRow),
			NeutralVsRow:  requirement_dao.ConvertKanoRow(req.KanoInfo.NeutralVsRow),
			TolerateVsRow: requirement_dao.ConvertKanoRow(req.KanoInfo.TolerateVsRow),
			DislikeVsRow:  requirement_dao.ConvertKanoRow(req.KanoInfo.DislikeVsRow),
		})
		if err != nil {
			return nil, err
		}
		err = requirement_dao.RequirementInfoDao.UpdateKanoState(sessCtx, req.ProjectId, req.RequirementId,
			&requirement_dao.KanoStatDbItem{
				Excite:   req.KanoExciteValue,
				Expect:   req.KanoExpectValue,
				Basic:    req.KanoBasicValue,
				Nodiff:   req.KanoNodiffValue,
				Reverse:  req.KanoReverseValue,
				Dubiouse: req.KanoDubiouseValue,
			})
		if err != nil {
			return nil, err
		}
		return &project_requirement_api.SetKanoInfoResponse{
			Code: project_requirement_api.SetKanoInfoResponse_CODE_OK,
		}, nil
	})
	if err != nil {
		return nil, err
	}
	//记录事件
	go apiImpl.addSetKanoInfoEvent(sessionItem, projectItem, reqItem, time.Now().UnixNano()/1e6)
	//发送通知
	go api_common.SendNoticeToProjectScope(context.Background(), req.ProjectId, &notices_requirement.UpdateRequirementNotice{
		ProjectId:     req.ProjectId,
		RequirementId: req.RequirementId,
	})
	return ret.(*project_requirement_api.SetKanoInfoResponse), nil
}

func (apiImpl *ProjectRequirementApiImpl) GetKanoInfo(ctx context.Context, req *project_requirement_api.GetKanoInfoRequest) (*project_requirement_api.GetKanoInfoResponse, error) {
	emptyInfo := &project_requirement_api.KanoInfo{
		RequirementId: req.RequirementId,
		LikeVsRow:     &project_requirement_api.KanoRow{},
		ExpectVsRow:   &project_requirement_api.KanoRow{},
		NeutralVsRow:  &project_requirement_api.KanoRow{},
		TolerateVsRow: &project_requirement_api.KanoRow{},
		DislikeVsRow:  &project_requirement_api.KanoRow{},
	}

	sessionItem, ok := dao.CacheDao.GetSession(ctx, req.SessionId)
	if !ok {
		return &project_requirement_api.GetKanoInfoResponse{
			Code:     project_requirement_api.GetKanoInfoResponse_CODE_WRONG_SESSION,
			ErrMsg:   "会话不存在",
			KanoInfo: emptyInfo,
		}, nil
	}
	_, _, _, err := utils.GetProjectMemberRole(ctx, req.ProjectId, sessionItem.UserId)
	if err == utils.ErrNoProject {
		return &project_requirement_api.GetKanoInfoResponse{
			Code:     project_requirement_api.GetKanoInfoResponse_CODE_NO_PROJECT,
			ErrMsg:   "项目不存在",
			KanoInfo: emptyInfo,
		}, nil
	} else if err == utils.ErrNoRole {
		return &project_requirement_api.GetKanoInfoResponse{
			Code:     project_requirement_api.GetKanoInfoResponse_CODE_NO_PERMISSION,
			ErrMsg:   "没有权限",
			KanoInfo: emptyInfo,
		}, nil
	} else if err != nil {
		return nil, err
	}

	exist, err := requirement_dao.RequirementInfoDao.Exist(ctx, req.ProjectId, req.RequirementId)
	if err != nil {
		return nil, err
	}
	if !exist {
		return &project_requirement_api.GetKanoInfoResponse{
			Code:     project_requirement_api.GetKanoInfoResponse_CODE_NO_REQUIRE_MENT,
			ErrMsg:   "需求不存在",
			KanoInfo: emptyInfo,
		}, nil
	}

	kanoItem, err := requirement_dao.KanoInfoDao.Get(ctx, req.RequirementId)
	if err != nil {
		return &project_requirement_api.GetKanoInfoResponse{
			Code:     project_requirement_api.GetKanoInfoResponse_CODE_OK,
			KanoInfo: emptyInfo,
		}, nil
	}
	return &project_requirement_api.GetKanoInfoResponse{
		Code:     project_requirement_api.GetKanoInfoResponse_CODE_OK,
		KanoInfo: kanoItem.ToKanoInfo(),
	}, nil
}

func (apiImpl *ProjectRequirementApiImpl) SetFourQInfo(ctx context.Context, req *project_requirement_api.SetFourQInfoRequest) (*project_requirement_api.SetFourQInfoResponse, error) {
	sessionItem, ok := dao.CacheDao.GetSession(ctx, req.SessionId)
	if !ok {
		return &project_requirement_api.SetFourQInfoResponse{
			Code:   project_requirement_api.SetFourQInfoResponse_CODE_WRONG_SESSION,
			ErrMsg: "会话不存在",
		}, nil
	}
	projectItem, _, roleItem, err := utils.GetProjectMemberRole(ctx, req.ProjectId, sessionItem.UserId)
	if err == utils.ErrNoProject {
		return &project_requirement_api.SetFourQInfoResponse{
			Code:   project_requirement_api.SetFourQInfoResponse_CODE_NO_PROJECT,
			ErrMsg: "项目不存在",
		}, nil
	} else if err == utils.ErrNoRole {
		return &project_requirement_api.SetFourQInfoResponse{
			Code:   project_requirement_api.SetFourQInfoResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	} else if err != nil {
		return nil, err
	}

	//检查需求是否存在
	reqItem, err := requirement_dao.RequirementInfoDao.Get(ctx, req.ProjectId, req.RequirementId)
	if err != nil {
		return &project_requirement_api.SetFourQInfoResponse{
			Code:   project_requirement_api.SetFourQInfoResponse_CODE_NO_REQUIRE_MENT,
			ErrMsg: "需求不存在",
		}, nil
	}

	if !(projectItem.OwnerUserId == sessionItem.UserId || roleItem.BasicInfo.Admin || sessionItem.UserId == reqItem.CreateUserId) {
		return &project_requirement_api.SetFourQInfoResponse{
			Code:   project_requirement_api.SetFourQInfoResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	}
	dbSess, err := dao.StartSession()
	if err != nil {
		return nil, err
	}
	defer dao.EndSession(dbSess)

	ret, err := dbSess.WithTransaction(ctx, func(sessCtx mongo.SessionContext) (interface{}, error) {
		err = requirement_dao.FourQInfoDao.Set(sessCtx, &requirement_dao.FourQInfoDbItem{
			RequirementId:            req.RequirementId,
			UrgentAndImportant:       req.FourQInfo.UrgentAndImportant,
			UrgentAndNotImportant:    req.FourQInfo.UrgentAndNotImportant,
			NotUrgentAndNotImportant: req.FourQInfo.NotUrgentAndNotImportant,
			NotUrgentAndImportant:    req.FourQInfo.NotUrgentAndImportant,
		})
		if err != nil {
			return nil, err
		}
		err = requirement_dao.RequirementInfoDao.UpdateFourQState(sessCtx, req.ProjectId, req.RequirementId, req.FourQUrgencyValue, req.FourQImportantValue)
		if err != nil {
			return nil, err
		}
		return &project_requirement_api.SetFourQInfoResponse{
			Code: project_requirement_api.SetFourQInfoResponse_CODE_OK,
		}, nil
	})
	if err != nil {
		return nil, err
	}
	//记录事件
	go apiImpl.addSetFourQInfoEvent(sessionItem, projectItem, reqItem, time.Now().UnixNano()/1e6)
	//发送通知
	go api_common.SendNoticeToProjectScope(context.Background(), req.ProjectId, &notices_requirement.UpdateRequirementNotice{
		ProjectId:     req.ProjectId,
		RequirementId: req.RequirementId,
	})
	return ret.(*project_requirement_api.SetFourQInfoResponse), nil
}

func (apiImpl *ProjectRequirementApiImpl) GetFourQInfo(ctx context.Context, req *project_requirement_api.GetFourQInfoRequest) (*project_requirement_api.GetFourQInfoResponse, error) {
	emptyInfo := &project_requirement_api.FourQInfo{
		RequirementId: req.RequirementId,
	}

	sessionItem, ok := dao.CacheDao.GetSession(ctx, req.SessionId)
	if !ok {
		return &project_requirement_api.GetFourQInfoResponse{
			Code:      project_requirement_api.GetFourQInfoResponse_CODE_WRONG_SESSION,
			ErrMsg:    "会话不存在",
			FourQInfo: emptyInfo,
		}, nil
	}
	_, _, _, err := utils.GetProjectMemberRole(ctx, req.ProjectId, sessionItem.UserId)
	if err == utils.ErrNoProject {
		return &project_requirement_api.GetFourQInfoResponse{
			Code:      project_requirement_api.GetFourQInfoResponse_CODE_NO_PROJECT,
			ErrMsg:    "项目不存在",
			FourQInfo: emptyInfo,
		}, nil
	} else if err == utils.ErrNoRole {
		return &project_requirement_api.GetFourQInfoResponse{
			Code:      project_requirement_api.GetFourQInfoResponse_CODE_NO_PERMISSION,
			ErrMsg:    "没有权限",
			FourQInfo: emptyInfo,
		}, nil
	} else if err != nil {
		return nil, err
	}

	exist, err := requirement_dao.RequirementInfoDao.Exist(ctx, req.ProjectId, req.RequirementId)
	if err != nil {
		return nil, err
	}
	if !exist {
		return &project_requirement_api.GetFourQInfoResponse{
			Code:      project_requirement_api.GetFourQInfoResponse_CODE_NO_REQUIRE_MENT,
			ErrMsg:    "需求不存在",
			FourQInfo: emptyInfo,
		}, nil
	}

	fourQItem, err := requirement_dao.FourQInfoDao.Get(ctx, req.RequirementId)
	if err != nil {
		return &project_requirement_api.GetFourQInfoResponse{
			Code:      project_requirement_api.GetFourQInfoResponse_CODE_OK,
			FourQInfo: emptyInfo,
		}, nil
	}
	return &project_requirement_api.GetFourQInfoResponse{
		Code:      project_requirement_api.GetFourQInfoResponse_CODE_OK,
		FourQInfo: fourQItem.ToFourQInfo(),
	}, nil
}
